Test and fix acknowedge_watch from returning EINVAL.
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Tue, 26 Jul 2005 15:09:43 +0000 (15:09 +0000)
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Tue, 26 Jul 2005 15:09:43 +0000 (15:09 +0000)
Also ensure that daemon re-xmits event if they ack wrong thing
(otherwise confused clients get stuck, as we will send no more
data while awaiting ack).
Signed-off-by: Rusty Russel <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
tools/xenstore/testsuite/13watch-ack.sh [new file with mode: 0644]
tools/xenstore/xenstored_core.c
tools/xenstore/xenstored_core.h
tools/xenstore/xenstored_watch.c

diff --git a/tools/xenstore/testsuite/13watch-ack.sh b/tools/xenstore/testsuite/13watch-ack.sh
new file mode 100644 (file)
index 0000000..70a7c6f
--- /dev/null
@@ -0,0 +1,22 @@
+#! /bin/sh
+
+# This demonstrates a bug where an xs_acknowledge_watch returns
+# EINVAL, because the daemon doesn't track what watch event it sent
+# and relies on it being the "first" watch which has an event.
+# Watches firing after the first event is sent out will change this.
+
+# Create three things to watch.
+echo mkdir /test | ./xs_test
+echo mkdir /test/1 | ./xs_test
+echo mkdir /test/2 | ./xs_test
+echo mkdir /test/3 | ./xs_test
+
+# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2.
+[ "`echo '1 watch /test/1 token1 0
+1 watch /test/2 token2 0
+1 watch /test/3 token3 0
+2 write /test/2 create contents2
+1 waitwatch
+2 write /test/1 create contents1
+2 write /test/3 create contents3
+1 ackwatch token2' | ./xs_test 2>&1`" = "1:/test/2:token2" ]
index e7c0c11d9d18b33882d5b4292b3a0a0173a2a178..3eac6407c5b5885b738fd34ea1022066ba4de7f7 100644 (file)
@@ -1166,7 +1166,7 @@ static void consider_message(struct connection *conn)
        /* We might get a command while waiting for an ack: this means
         * the other end discarded it: we will re-transmit. */
        if (type != XS_WATCH_ACK)
-               conn->waiting_for_ack = false;
+               conn->waiting_for_ack = NULL;
 
        /* Careful: process_message may free connection.  We detach
         * "in" beforehand and allocate the new buffer to avoid
index 2a5a2b02f52f296f9eb5e1084fb400c49991bdfa..4aae32e95e9ec75251cca3a2a179d60f640d1e7f 100644 (file)
@@ -64,7 +64,7 @@ struct connection
        bool can_write;
 
        /* Are we waiting for a watch event ack? */
-       bool waiting_for_ack;
+       struct watch *waiting_for_ack;
 
        /* Buffered incoming data. */
        struct buffered_data *in;
index 6945dd91e0358227adcb2a8d16e2216f2b1246a8..70bfbaa595a93bb1c7e7a7ee064d01a2e457ceac 100644 (file)
@@ -102,7 +102,7 @@ void queue_next_event(struct connection *conn)
        if (conn->waiting_reply) {
                conn->out = conn->waiting_reply;
                conn->waiting_reply = NULL;
-               conn->waiting_for_ack = false;
+               conn->waiting_for_ack = NULL;
                return;
        }
 
@@ -115,7 +115,7 @@ void queue_next_event(struct connection *conn)
                return;
 
        /* If we decide to cancel, we will reset this. */
-       conn->waiting_for_ack = true;
+       conn->waiting_for_ack = event->watches[0];
 
        /* If we deleted /foo and they're watching /foo/bar, that's what we
         * tell them has changed. */
@@ -348,12 +348,17 @@ bool do_watch_ack(struct connection *conn, const char *token)
        if (!conn->waiting_for_ack)
                return send_error(conn, ENOENT);
 
-       event = get_first_event(conn);
-       if (!streq(event->watches[0]->token, token))
+       event = list_top(&conn->waiting_for_ack->events,
+                        struct watch_event, list);
+       assert(event->watches[0] == conn->waiting_for_ack);
+       if (!streq(conn->waiting_for_ack->token, token)) {
+               /* They're confused: this will cause us to send event again */
+               conn->waiting_for_ack = NULL;
                return send_error(conn, EINVAL);
+       }
 
        move_event_onwards(event);
-       conn->waiting_for_ack = false;
+       conn->waiting_for_ack = NULL;
        return send_ack(conn, XS_WATCH_ACK);
 }